package by.dvrudenko.avtobaza.dataaccess.impl;

import java.util.ArrayList;
import java.util.List;

import javax.management.RuntimeErrorException;
import javax.persistence.TypedQuery;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import javax.persistence.metamodel.SingularAttribute;

import org.apache.commons.lang3.Validate;
import org.hibernate.engine.internal.TwoPhaseLoad;
import org.hibernate.jpa.criteria.OrderImpl;
import org.springframework.aop.framework.adapter.ThrowsAdviceInterceptor;
import org.springframework.stereotype.Repository;

import by.dvrudenko.avtobaza.dataaccess.UserOrderDao;
import by.dvrudenko.avtobaza.datamodel.Route;
import by.dvrudenko.avtobaza.datamodel.Route_;
import by.dvrudenko.avtobaza.datamodel.UserOrder;
import by.dvrudenko.avtobaza.datamodel.UserOrder_;
import by.dvrudenko.avtobaza.datamodel.User_;
import by.dvrudenko.avtobaza.datamodel.enums.OrderStatus;


@Repository
public class UserOrderDaoImpl extends AbstractDaoImpl<Long, UserOrder> implements UserOrderDao {

	
	public UserOrderDaoImpl() {
		super(UserOrder.class);
	}
	
	 @Override
	    public List<UserOrder> getAllUserOrders() {
	        CriteriaBuilder cBuilder = getEm().getCriteriaBuilder();

	        CriteriaQuery<UserOrder> criteria = cBuilder.createQuery(UserOrder.class);
	        Root<UserOrder> root = criteria.from(UserOrder.class);

	        criteria.select(root);
	        root = prepareRoot(root);
	        
	        TypedQuery<UserOrder> query = getEm().createQuery(criteria);
	        List<UserOrder> results = query.getResultList();
	        return results;
	    }

	    @Override
	    public Long getCount(Long UserId) {
	        CriteriaBuilder cBuilder = getEm().getCriteriaBuilder();

	        CriteriaQuery<Long> criteria = cBuilder.createQuery(Long.class);
	        Root<UserOrder> root = criteria.from(UserOrder.class);
	        
			if (UserId!=null){
				criteria.where(cBuilder.equal(root.get(UserOrder_.user), UserId));
			}

	        criteria.select(cBuilder.count(root));

	        TypedQuery<Long> query = getEm().createQuery(criteria);
	        return query.getSingleResult();
	    }

	    /*
	     * 'select all' with sorting and paging example.
	     */
	    @Override
	    public List<UserOrder> getAllUserOrders(SingularAttribute<UserOrder, ?> attr, boolean ascending, int startRecord,
	    		int pageSize, Long UserId) {
	        CriteriaBuilder cBuilder = getEm().getCriteriaBuilder();

	        CriteriaQuery<UserOrder> criteria = cBuilder.createQuery(UserOrder.class);
	        Root<UserOrder> root = criteria.from(UserOrder.class);

	        criteria.select(root);
	        root = prepareRoot(root);
	        if(UserId!=null){
	        	criteria.where(cBuilder.equal(root.get(UserOrder_.user), UserId));
	        }
	        criteria.orderBy(new OrderImpl(root.get(attr), ascending));
	        

	        TypedQuery<UserOrder> query = getEm().createQuery(criteria);
	        query.setFirstResult(startRecord);
	        query.setMaxResults(pageSize);

	        List<UserOrder> results = query.getResultList();
	        return results;
	    }

		@Override // недописал метод не получается сделать условие
		public UserOrder getRandomOrder() {
	        CriteriaBuilder cBuilder = getEm().getCriteriaBuilder();

	        CriteriaQuery<UserOrder> criteria = cBuilder.createQuery(UserOrder.class);
	        Root<UserOrder> root = criteria.from(UserOrder.class);
	        
	        criteria.select(root);
	        root = prepareRoot(root);
	        
	        Predicate predicates1 = cBuilder.equal(root.get(UserOrder_.orderStatus), 
	        		OrderStatus.pick_up_cargo);
	        Predicate predicates2 =  cBuilder.equal(root.get(UserOrder_.orderStatus),
    				OrderStatus.rides_for_cargo);       
	        
	        
	        criteria.where(cBuilder.or(predicates1,predicates2));
	        
		/*	criteria.where(cBuilder.or(
					cBuilder.equal(root.get(UserOrder_.orderStatus), OrderStatus.pick_up_cargo),
					cBuilder.equal(root.get(UserOrder_.orderStatus), OrderStatus.rides_for_cargo)));*/
					
	        TypedQuery<UserOrder> query = getEm().createQuery(criteria);
	        List<UserOrder> results = query.getResultList();
	                    
			return results.get(1);
		}
		
		@Override
		public List<UserOrder> getAllActiveOrderByStatus(OrderStatus orderStatus) {
			CriteriaBuilder cBuilder = getEm().getCriteriaBuilder();
		    CriteriaQuery<UserOrder> criteria = cBuilder.createQuery(UserOrder.class);
		    Root<UserOrder> root = criteria.from(UserOrder.class);
		    criteria.select(root);    
		    root = prepareRoot(root);    
		    
			criteria.where(cBuilder.and(cBuilder.equal(root.get(UserOrder_.orderStatus), orderStatus)));
		
		    criteria.distinct(true);

		    TypedQuery<UserOrder> query = getEm().createQuery(criteria);
		    List<UserOrder> results = query.getResultList();
			return results;
		}
		
		private Root<UserOrder> prepareRoot(Root<UserOrder> root){
        root.fetch(UserOrder_.cargoBeginningCity);
        root.fetch(UserOrder_.cargoFinalCity);
        root.fetch(UserOrder_.user);
        return root;
        
		}
}
